#pragma once
#include <iostream>
#include <string>
#include <unordered_map>
#include <functional>
#include "Socket.h"
#include "Log.hpp"
#include "Epoll.hpp"

class Connection;
class TcpServer;

using func_t = std::function<void(Connection *)>;
using callback_t = std::function<void(Connection *, std::string &request)>;

// 建立缓冲区联系
class Connection
{
public:
    Connection(int sock = -1) : _sock(sock), _tsvr(nullptr) {}

    ~Connection() {}

    // 调用函数
    void SetCallBack(func_t recv_cb, func_t send_cb, func_t except_cb)
    {
        _recv_cb = recv_cb;
        _send_cb = send_cb;
        _except_cb = except_cb;
    }

public:
    // 套接字连接
    int _sock;
    // 回调函数
    func_t _recv_cb;
    func_t _send_cb;
    func_t _except_cb;
    // 接收缓冲区&&发送缓冲区
    std::string _inbuf;
    std::string _outbuf;
    // 回值指针
    TcpServer *_tsvr;

    // 时间戳,解决长时间连接未响应问题
    uint64_t _lasttimestamp; // time();
};

class TcpServer
{
    const static int gport = 8080;
    const static int gnum = 128;

public:
    TcpServer(const int port = gport, int revs_num = gnum)
        : _port(port), _revs_num(revs_num)
    {
        // 建立网络连接
        _listensock = Sock().Socket();
        Sock().Bind(_listensock, _port);
        Sock().Listen(_listensock);

        // 添加多路转接对象
        _epoll.EpollCreater();

        // 3. 添加listensock到服务器中
        AddConnection(_listensock, std::bind(&TcpServer::Accepter, this, std::placeholders::_1), nullptr, nullptr);

        // 4. 构建一个获取就绪事件的缓冲区
        _revs = new struct epoll_event[_revs_num];
    }

    void AddConnection(int sock, func_t recv_cb, func_t send_cb, func_t except_cb)
    {
        Sock().SetNonBlock(sock);                       // 设为非阻塞
        Connection *conn = new Connection(sock);        // 添加缓冲区
        conn->SetCallBack(recv_cb, send_cb, except_cb); // 回调方法
        conn->_tsvr = this;
        // conn->_lasttimestamp = time();
        //  2. 添加sock到epoll中
        _epoll.AddSockToEpoll(sock, EPOLLIN | EPOLLET); // 任何多路转接的服务器，一般默认只会打开对读取事件的关心，写入事件会按需进行打开！
        // 3. 还要将对应的Connection*对象指针添加到Connections映射表中！
        _connections.insert(std::make_pair(sock, conn));
    }
    void Accepter(Connection *conn)
    {
        while (true)
        {
            std::string clickip;
            uint16_t clickport;
            int accept_errno = 0;
            int sock = Sock().Accept(conn->_sock, &clickport, &clickip, &accept_errno);
            if (sock < 0)
            {
                if (accept_errno == EAGAIN || accept_errno == EWOULDBLOCK)
                    break;
                else if (accept_errno == EINTR)
                    continue; // 概率非常低,中断
                else
                {
                    // accept失败
                    logMessage(WARING, "accept error, %d : %s", accept_errno, strerror(accept_errno));
                    break;
                }
            }
            // 将sock托管给TcpServer
            if (sock >= 0)
            {
                AddConnection(sock, std::bind(&TcpServer::Recver, this, std::placeholders::_1),
                              std::bind(&TcpServer::Sender, this, std::placeholders::_1),
                              std::bind(&TcpServer::Excepter, this, std::placeholders::_1));
                logMessage(DEBUG, "accept client %s:%d success, add to epoll&&TcpServer success, sock: %d",
                           clickip.c_str(), clickport, sock);
            }
        }
    }
    void Recver(Connection *conn)
    {
        bool err=false;
       while(true)
       {
            char buff[1024];
            ssize_t n = recv(conn->_sock, buff, sizeof(buff) - 1, 0);
            if (n > 0)
            {
                buff[n] = 0;
                conn->_inbuf += buff;
            }
            else if (n == 0)
            {
                logMessage(DEBUG, "client[%d] quit, server close [%d]", conn->_sock, conn->_sock);
                conn->_except_cb(conn);
                err = true;
                break;
            }
       }
    }
    void Sender(Connection *conn)
    {
        while(true)
        {
            ssize_t n = send(conn->_sock, conn->_outbuf.c_str(), conn->_outbuf.size(), 0);

        }
        //不知道是否发送完
        if(conn->_outbuf.empty()) 
            EnableReadWrite(conn, true, false);
        else EnableReadWrite(conn, true, true);

    }
    void Excepter(Connection *conn)
    {
        ;
    }
    void LoopOnce()//处理事件
    {
        int n = _epoll.WaitPoll(_revs, _revs_num); // 时间个数
        for (int i = 0; i < n; i++)
        {
            int sock = _revs[i].data.fd;
            uint32_t revents = _revs[i].events;

            if (revents & EPOLLERR)
                revents |= (EPOLLIN | EPOLLOUT);
            if (revents & EPOLLHUP)
                revents |= (EPOLLIN | EPOLLOUT);

            if (revents & EPOLLIN)
            {
                if (IsConnectionExists(sock) && _connections[sock]->_recv_cb != nullptr)
                    _connections[sock]->_recv_cb(_connections[sock]);
            }
            if (revents & EPOLLOUT)
            {
                if (IsConnectionExists(sock) && _connections[sock]->_send_cb != nullptr)
                    _connections[sock]->_send_cb(_connections[sock]);
            }
        }
    }
    void EnableReadWrite(Connection *conn, bool readable, bool writeable)
    {
        uint32_t events = ((readable ? EPOLLIN : 0) | (writeable ? EPOLLOUT : 0));
        bool res = _epoll.CtrlEpoll(conn->_sock, events);
        assert(res); //更改成if
    }
    
    void Dispather(callback_t cb)
    {
        _cb=cb;
        while (true)
        {
            LoopOnce();
        }
    }
    bool IsConnectionExists(int sock)
    {
        ;
    }
    ~TcpServer()
    {
        if (_listensock >= 0)
            close(_listensock);
        if (_revs)
            delete[] _revs;
    }

private:
    uint16_t _port;
    int _listensock;                                    // 网络
    Epoll _epoll;                                       // epoll
    std::unordered_map<int, Connection *> _connections; // 存储
    struct epoll_event *_revs;                          // 构建数组
    int _revs_num;                                      // 最大数

    callback_t _cb;
};
